home *** CD-ROM | disk | FTP | other *** search
/ The 640 MEG Shareware Studio 2 / The 640 Meg Shareware Studio CD-ROM Volume II (Data Express)(1993).ISO / clang / nn.zip / RC.C < prev    next >
C/C++ Source or Header  |  1989-12-31  |  14KB  |  641 lines

  1. /*
  2.  * rc management routines
  3.  */
  4.  
  5. #include "config.h"
  6. #include "term.h"
  7. #include "debug.h"
  8.  
  9. export int  keep_rc_backup = 1;
  10. export int  no_update = 0;
  11. export int  use_newsrc = 0;
  12.  
  13. export long unread_articles;    /* estimate of unread articles */
  14. export int  unread_groups;
  15.  
  16.  
  17. static FILE *rc = NULL;        /* rc_file descriptor */
  18.  
  19. static char RC[] = "rc";
  20. static char BAK[] = "rc.bak";
  21. static char NEWSRC[] = ".newsrc";
  22.  
  23. static int  has_newsrc = 0;
  24.  
  25. /* RC lines have the format:  */
  26. /*    SUBSCR space LASTART space GROUPNUM space NAME */
  27.  
  28. #define    SUBSCRZ            1
  29. #define    SUBSCRPOS        0
  30. #define SUBSCR(buf)        buf[0]
  31.  
  32. /* NOTICE THAT LASTARTZ IS HARDCODED IN A printf FORMAT STRING LATER ON */
  33.  
  34. #define LASTARTZ        6
  35. #define    LASTARTPOS        (SUBSCRPOS + SUBSCRZ + 1)
  36. #define    LASTART(buf)        atol(buf + LASTARTPOS)
  37.  
  38. #define GROUPNAMEPOS        (LASTARTPOS + LASTARTZ + 1)
  39. #define    GROUPNAME(buf)        (buf + GROUPNAMEPOS)
  40.  
  41. #define    NEW_OFFSET    ((off_t)1)    /* append to rc_file when written */
  42.  
  43. /*
  44.  * read rc file info to group headers
  45.  * master file has been read in
  46.  */
  47.  
  48. #define    G_OLD    G_SELECTION
  49. #define G_RENUM    G_DONE
  50.  
  51.  
  52. visit_rc_file()
  53. {
  54.     FILE *bak, *newsrc;
  55.     register int c;
  56.     register group_header *gh;
  57.     register char *cp;
  58.     char line[512];
  59.     off_t rcpos;        /* position in rc */
  60.     int warn_duplicates = 0, mk_bak, rd_newsrc, bak_used;
  61.     time_t m_rc, m_newsrc;
  62.     char rc_path[FILENAME], bak_path[FILENAME];
  63.     
  64.     strcpy(rc_path, relative(nn_directory, RC));
  65.     strcpy(bak_path, relative(nn_directory, BAK));
  66.  
  67.     rc = NULL;    /* open rc-file */
  68.     rewind_rc(rc_path, OPEN_READ);
  69.  
  70.     m_rc = 0;
  71.     if (rc != NULL) {
  72.     fseek(rc, (off_t)0, 2);
  73.     if (ftell(rc) > (off_t)0) {
  74.         fseek(rc, 0L, 0);
  75.             m_rc = m_time(rc);
  76.     }
  77.     }
  78.     
  79.     rd_newsrc = use_newsrc;
  80.     m_newsrc = 0;
  81.     mk_bak = keep_rc_backup;
  82.     bak_used = 0;
  83.     
  84.     if (m_rc == 0) {        /* rc empty (i.e. new or corrupted) */
  85.     if ((bak = open_file(bak_path, OPEN_READ)) != NULL) {
  86.         m_rc = m_time(bak);
  87.         if (m_rc >= m_newsrc) {
  88.         printf("\nRestoring %s from %s\n", RC, BAK);
  89.         rewind_rc(rc_path, OPEN_CREATE | MUST_EXIST);
  90.         while ((c = getc(bak)) != EOF) putc(c, rc);
  91.         rewind_rc(rc_path, OPEN_READ | MUST_EXIST);
  92.         fclose(bak);
  93.         mk_bak = 0;
  94.         bak_used = 1;
  95.         }
  96.     } else {
  97.         rd_newsrc = 1;
  98.         display_help("welcome");
  99.     }
  100.     }
  101.  
  102.     if (rd_newsrc) {
  103.     newsrc = open_file(relative(home_directory, NEWSRC), OPEN_READ);
  104.     if (newsrc != NULL) {
  105.         m_newsrc = m_time(newsrc);
  106.         has_newsrc = 1;
  107.     }
  108.     }
  109.     
  110.     if (has_newsrc) {
  111.     if (m_rc < m_newsrc) {
  112.         if (bak_used) {
  113.         printf("\n%s is newer than %s -- use %s ? ",
  114.                NEWSRC, BAK, NEWSRC);
  115.         fl;
  116.         if (!yes(0)) m_newsrc = 0;
  117.         }
  118.  
  119.         if (m_newsrc != 0) {
  120.         
  121.         printf("\nReading from %s\n", NEWSRC);
  122.  
  123.         if (m_rc != 0) {
  124.             fclose(rc);
  125.             rc = NULL;
  126.             
  127.             unlink(bak_path);
  128.             if (link(rc_path, bak_path) < 0 || unlink(rc_path) < 0)
  129.             user_error("Cannot backup %s file\n", RC);
  130.             
  131.             mk_bak = 0;
  132.         }    
  133.         
  134.         rewind_rc(rc_path, OPEN_CREATE | MUST_EXIST);
  135.         read_newsrc(newsrc);
  136.         rewind_rc(rc_path, OPEN_READ | MUST_EXIST);
  137.         }
  138.     }
  139.     
  140.     fclose(newsrc);
  141.     }
  142.     
  143.     if (rc == NULL) {        /* no .nn/rc and no .newsrc */
  144.     bak = NULL;
  145.     goto endloop;
  146.     }
  147.     
  148.     if (no_update) mk_bak = 0;
  149.  
  150.     bak = mk_bak ? open_file(bak_path, OPEN_CREATE | MUST_EXIST) : NULL;
  151.  
  152.     for(;;) {
  153.     rcpos = ftell(rc);
  154.     
  155.     c = getc(rc);
  156.     
  157.     cp = line;
  158.     while (c != NL) {
  159.         if (c == EOF) goto endloop;
  160.         *cp++ = c;
  161.         c = getc(rc);
  162.     }
  163.     *cp = NUL;
  164.     if (bak != NULL) {
  165.         fputs(line, bak);
  166.         fputc(NL, bak);
  167.     }
  168.     
  169.     if (SUBSCR(line) != '+' && SUBSCR(line) != '!' && SUBSCR(line) != '=') {
  170.         /* unrecognized line */
  171.         continue;
  172.     }
  173.     
  174.     if ((gh = lookup(GROUPNAME(line))) == NULL) continue;
  175.  
  176.     if (gh->group_flag & G_OLD) {
  177.         printf("Duplicated entry in rc file: %s\n", gh->group_name);
  178.         warn_duplicates++;
  179.     }
  180.     gh->rc_offset = rcpos;
  181.     
  182.     gh->group_flag |= G_OLD;
  183.     if (SUBSCR(line) == '+')
  184.         gh->group_flag |= G_SUBSCRIPTION;
  185.     if (SUBSCR(line) == '=')
  186.         gh->group_flag |= G_SUBSCRIPTION | G_NEW;
  187.  
  188.     gh->last_article = LASTART(line);
  189.  
  190.     if (gh->group_flag & (G_BLOCKED | G_NO_DIRECTORY)) {
  191.         /* We cannot trust this group, so we leave it alone */
  192.         /* group_menu after update_group will do what is necessary */
  193.         continue;
  194.     }
  195.     
  196.     if (gh->last_article > gh->last_l_article)
  197.         gh->group_flag |= G_RENUM;    /* mark for use below */
  198.     
  199.     if (gh->first_l_article > gh->last_article ||
  200.         gh->last_article > gh->last_l_article)
  201.         gh->last_article = gh->first_l_article - 1;
  202.     
  203.     if (gh->last_article < 0) gh->last_article = 0;
  204.     }    
  205.  
  206. endloop:
  207.     if (warn_duplicates) {
  208.     printf("You can repair this using \"nntidy\"\n");
  209.     any_key(0);
  210.     }    
  211.  
  212.     rewind_rc(rc_path, OPEN_UPDATE | MUST_EXIST);
  213.  
  214.     Loop_Groups_Header(gh) {
  215.     if (gh->group_flag & G_OLD) {
  216.         if (gh->group_flag & G_RENUM) /* group is renumbered */
  217.         write_rc_entry(gh, 0);
  218.         gh->group_flag &= ~(G_OLD | G_RENUM);
  219.     } else {
  220.         gh->group_flag |= G_SUBSCRIPTION | G_NEW;
  221.         gh->last_article = gh->first_l_article - 1;
  222.         if (gh->last_article < 0) gh->last_article = 0;
  223.         gh->rc_offset = NEW_OFFSET;
  224.     }
  225.     gh->first_article = gh->last_article;
  226.     }
  227.     
  228.     if (bak != NULL) fclose(bak);
  229.     
  230.     if (no_update) {
  231.     fclose(rc);
  232.     rc = NULL;
  233.     } else
  234.     fflush(rc);
  235. }
  236.  
  237.  
  238. rewind_rc(path, mode)
  239. char *path;
  240. {
  241.     if (rc != NULL) fclose(rc);
  242.     rc = open_file(path, mode);
  243. }
  244.  
  245.  
  246. restore_bak()
  247. {
  248.     if (no_update) 
  249.     return 1;
  250.     
  251.     if (!keep_rc_backup) {
  252.     msg("No %s file ('backup' is not set)", BAK);
  253.     return 0;
  254.     }
  255.  
  256.     prompt("Are you sure? ");
  257.     if (!yes(1)) return 0;
  258.     
  259.     fclose(rc);    /* cannot use close_rc() since it would update .newsrc */
  260.     rc = NULL;
  261.     
  262.     if (chdir(nn_directory) < 0) goto err;
  263.  
  264.     if (unlink(RC) < 0) goto err;
  265.     if (link(BAK, RC) < 0) goto err;
  266.     if (unlink(BAK) < 0) goto err;
  267.     
  268.     return 1;
  269.  
  270.  err:
  271.     clrdisp();
  272.     printf("Restore of %s file failed\n\n", RC);
  273.     printf("Check state of %s and %s files\n", RC, BAK);
  274.     nn_exit(1);
  275.     /*NOTREACHED*/
  276. }
  277.  
  278. update_rc(gh)
  279. register group_header *gh;
  280. {
  281.     add_unread(gh, -1);
  282.  
  283.     if (no_update || gh->group_flag & G_READ) return;
  284.  
  285.     gh->last_article = gh->last_l_article;
  286.  
  287. #ifdef RC_TEST    
  288.     if (Debug & RC_TEST) 
  289.     fprintf(stderr, "upd_rc(%s) pos=%ld, artno=%ld\n",
  290.         gh->group_name, gh->rc_offset, gh->last_article);
  291. #endif
  292.  
  293.     write_rc_entry(gh, 0);
  294.     
  295.     gh->group_flag |= G_READ;
  296. }
  297.  
  298.  
  299. restore_rc(gh, count)
  300. register group_header *gh;
  301. long count;
  302. {
  303.     if (no_update || (count == 0 && (gh->group_flag & G_READ) == 0))
  304.     return 0;
  305.  
  306.     if (gh->group_flag & G_READ || count > 0) {
  307.     add_unread(gh, -1);
  308.     
  309.     if (count > 0) {
  310.         gh->last_article = gh->last_l_article - count;
  311.         if (gh->last_article < gh->first_l_article)
  312.         gh->last_article = gh->first_l_article - 1;
  313.         gh->first_article = gh->last_article;
  314.     } else
  315.         gh->last_article = gh->first_article;
  316.  
  317. #ifdef RC_TEST    
  318.     if (Debug & RC_TEST) 
  319.         fprintf(stderr, "restore_rc(%s) pos=%ld, artno=%ld\n",
  320.             gh->group_name, gh->rc_offset, gh->last_article);
  321. #endif
  322.  
  323.     write_rc_entry(gh, 0);
  324.     
  325.     gh->group_flag &= ~G_READ;
  326.     
  327.     add_unread(gh, 1);
  328.     
  329.     return 1;
  330.     }
  331.     return 0;
  332. }
  333.  
  334.  
  335. close_rc()
  336. {
  337.     off_t endrc;
  338.     
  339.     if (rc == NULL) return;
  340.     
  341.     if (use_newsrc) {
  342.     write_newsrc();
  343.  
  344.     fflush(rc);
  345.     fseek(rc, 0L, 2);    /* touch rc file */
  346.     if ((endrc = ftell(rc)) == 0)
  347.         fprintf(rc, "#\n");
  348.     else {
  349.         fflush(rc);
  350.         fseek(rc, endrc - 1, 0);
  351.         fputc(NL, rc);
  352.     }
  353.     }
  354.     
  355.     fclose(rc);
  356.     rc = NULL;
  357. }
  358.  
  359.  
  360.  
  361. count_unread_articles(trace)
  362. int trace;
  363. {
  364.     register group_header *gh;
  365.     long n;
  366.     
  367.     unread_articles = 0;
  368.     unread_groups = 0;
  369.     
  370.     Loop_Groups_Sequence(gh) {
  371.     gh->group_flag &= ~G_UNREAD_COUNT;
  372.  
  373.     if ((gh->group_flag & G_SUBSCRIPTION) == 0) continue;
  374.     if (gh->group_flag & G_NO_DIRECTORY) continue;
  375.  
  376.     if (gh->last_l_article > gh->last_article) {
  377.         n = unread_articles;
  378.         add_unread(gh, 1);
  379.         if (trace)
  380.         printf("%6d %s\n", unread_articles - n, gh->group_name);
  381.     }
  382.     }
  383. }
  384.  
  385.  
  386. prt_unread(format)
  387. register char *format;
  388. {
  389.     if (format == NULL) {
  390.     printf("No News (is good news)\n");
  391.     return;
  392.     }
  393.     
  394.     while (*format) {
  395.     if (*format != '%') {
  396.         putchar(*format++);
  397.         continue;
  398.     }
  399.     format++;
  400.     switch (*format++) {
  401.      case 'u':
  402.         printf("%ld unread article%s", 
  403.            unread_articles, 
  404.            unread_articles == 1 ? "" : "s");
  405.         continue;
  406.      case 'g':
  407.         printf("%d group%s",
  408.            unread_groups, 
  409.            unread_groups == 1 ? "" : "s");
  410.         continue;
  411.      case 'i':
  412.         printf(unread_articles == 1 ? "is" : "are");
  413.         continue;
  414.      case 'U':
  415.         printf("%ld", unread_articles);
  416.         continue;
  417.      case 'G':
  418.         printf("%d", unread_groups);
  419.         continue;
  420.     }
  421.     }
  422. }
  423.  
  424.  
  425. add_unread(gh, mode)
  426. group_header *gh;
  427. int mode;    /* +1 => add, -1 => subtract */
  428. {
  429.     long art;
  430.     int32 was_unread;
  431.     
  432.     art = gh->last_l_article - gh->last_article;
  433.     was_unread = (gh->group_flag & G_UNREAD_COUNT);
  434.     
  435.     if (mode > 0) {
  436.     if (was_unread) return 0;
  437.     unread_articles += art;
  438.     unread_groups++;
  439.     gh->group_flag |= G_UNREAD_COUNT;
  440.     } else {
  441.     if (!was_unread) return 0;
  442.     unread_articles -= art;
  443.     unread_groups--;
  444.     gh->group_flag &= ~G_UNREAD_COUNT;
  445.     }    
  446.     
  447.     return (was_unread != 0);
  448. }
  449.  
  450.  
  451. /*
  452.  * write one line on rc_file
  453.  */
  454.  
  455. write_rc_entry(gh, new)
  456. group_header *gh;
  457. int new;    /* 0 => old, 1 => quick append, 2 => normal append */
  458. {
  459.     if (gh->rc_offset == NEW_OFFSET) new = 2;
  460.     
  461.     if (new) {
  462.     if (new == 2) fseek(rc, (off_t)0, 2);
  463.     gh->rc_offset = ftell(rc);
  464.     } else
  465.     if (fseek(rc, gh->rc_offset, 0) < 0)
  466.         user_error("Seek error on %s file", RC);
  467.  
  468.     /*
  469.      * the 'last article' is not updated in the rc file
  470.      * when a group is unsubscribed; if it is later resubscribed,
  471.      * the present articles will still be unread (if they exist)
  472.      */
  473.  
  474.     /* update article number */
  475.     
  476.     fprintf(rc, "%c %06ld",    /* MUST CHANGE IF LASTARTZ CHANGES */
  477.         (gh->group_flag & G_NEW) ? '=' :
  478.         (gh->group_flag & G_SUBSCRIPTION) ? '+' : '!',
  479.         (long)(gh->last_article));
  480.  
  481.     if (new) {
  482.     fputc(' ', rc);
  483.     fputs(gh->group_name, rc);
  484.     fputc(NL, rc);
  485.     }
  486.  
  487.     fflush(rc);
  488. }
  489.  
  490.  
  491. /*
  492.  * Old-style .newsrc support
  493.  */
  494.  
  495. static read_newsrc(newsrc)
  496. FILE *newsrc;
  497. {
  498.     copy_newsrc(newsrc, (FILE *)NULL);
  499. }
  500.  
  501. static write_newsrc()
  502. {
  503.     char newsrc_path[FILENAME], bak_path[FILENAME];
  504.     FILE *newsrc, *bak;
  505.     
  506.     strcpy(newsrc_path, relative(home_directory, NEWSRC));
  507.     sprintf(bak_path, "%s.bak", newsrc_path);
  508.     
  509.     if (has_newsrc) {
  510.     unlink(bak_path);
  511.     if (link(newsrc_path, bak_path) < 0 || unlink(newsrc_path) < 0)
  512.         user_error("Cannot backup %s file\n", newsrc_path);
  513.  
  514.     bak = open_file(bak_path, OPEN_READ | MUST_EXIST);
  515.     } else
  516.     bak = NULL;
  517.  
  518.     if (file_exist(newsrc_path, (char *)NULL)) {
  519.     /* This is real paranoia ... don't let people lose their .newsrc */
  520.     /* This should not happen - but it has been seen */
  521.     log_entry('E', "failed to backup %s", newsrc_path);
  522.     fprintf(stderr, "PROBLEM... YOUR %s WAS NOT UPDATED\n", NEWSRC);
  523.     if (bak != NULL) fclose(bak);
  524.     return;
  525.     }
  526.     
  527.     newsrc = open_file(newsrc_path, OPEN_CREATE | MUST_EXIST);
  528.     copy_newsrc(bak, newsrc);
  529.     if (bak != NULL) fclose(bak);
  530.     fclose(newsrc);
  531. }
  532.  
  533. static copy_newsrc(old_rc, new_rc)
  534. FILE *old_rc, *new_rc;
  535. {
  536.     char buf[2048];
  537.     char *sub, *last, subscr;
  538.     long atol();
  539.     register group_header *gh;
  540.     
  541.     Loop_Groups_Header(gh)
  542.     gh->group_flag &= ~G_DONE;
  543.  
  544.     if (old_rc != NULL) {
  545.     /* NEWSRC lines have the following format         */
  546.     /*    NAME(n)SUBSCR(1) space NUM[,NUM][-NUM]...     */
  547.  
  548.     while (fgets(buf, 2048, old_rc) != NULL) {
  549.         subscr = 0;
  550.         if (sub = strchr(buf, ':'))
  551.         subscr = 1;
  552.         else 
  553.         sub = strchr(buf, '!');
  554.         
  555.         if (sub == NULL) {
  556.         if (new_rc != NULL) goto output_unchanged;
  557.         continue;
  558.         }
  559.         
  560.         *sub = NUL;
  561.         gh = lookup(buf);
  562.         *sub++ = subscr ? ':' : '!';
  563.         
  564.         if (gh == NULL) {
  565.         if (new_rc != NULL) goto output_unchanged;
  566.         continue;
  567.         }
  568.         
  569.         if (new_rc != NULL) {
  570.         if (gh->group_flag & G_DONE) continue;
  571.         gh->group_flag |= G_DONE;
  572.         if (!subscr) goto output_unchanged;
  573.         write_newsrc_entry(new_rc, gh, (*sub == NL) ? 1 : 0);
  574.         continue;
  575.         }
  576.         
  577.         /* Notice: unread articles before the last read article are lost */
  578.         
  579.         if (subscr) {
  580.         if (*sub == NL) continue; /* new group */
  581.         
  582.         last = strrchr(sub, '-');
  583.         if (last == NULL) last = strrchr(sub, ',');
  584.         if (last == NULL) last = strrchr(sub, ' ');
  585.         if (last == NULL) last = "0"; else last++;
  586.         
  587.         gh->last_article = atol(last);
  588.         gh->group_flag |= G_SUBSCRIPTION;
  589.         } else
  590.         gh->last_article = 0;
  591.         
  592.         gh->rc_offset = NEW_OFFSET;
  593.         
  594.         write_rc_entry(gh, 0);
  595.         continue;
  596.         
  597.      output_unchanged:
  598.         fputs(buf, new_rc);
  599.     }
  600.     }    
  601.  
  602.     Loop_Groups_Header(gh) {
  603.     if (new_rc != NULL) {
  604.         if (gh->group_flag & G_DONE) continue;
  605.         write_newsrc_entry(new_rc, gh, -1);
  606.     } else {
  607.         gh->rc_offset = 0;
  608.         gh->last_article = 0;
  609.         gh->group_flag &= G_MASTER_FLAGS;
  610.     }
  611.     }
  612.  
  613.     return 1;
  614. }
  615.  
  616. write_newsrc_entry(newsrc, gh, also_new)
  617. FILE *newsrc;
  618. register group_header *gh;
  619. int also_new;
  620. {
  621.     if ((gh->group_flag & G_READ) == 0 && (gh->group_flag & G_NEW)) {
  622.     if (also_new < 0) return;
  623.     } else
  624.     also_new = 0;
  625.     
  626.     fprintf(newsrc, "%s%c", gh->group_name,
  627.         (gh->group_flag & G_SUBSCRIPTION) ? ':' : '!');
  628.  
  629.     if (also_new) {
  630.     fputc(NL, newsrc);
  631.     return;
  632.     }
  633.     
  634.     if (gh->first_l_article > gh->last_article) 
  635.     fprintf(newsrc, " %s%d\n", 
  636.         gh->first_l_article > 2 ? "1-" : "",
  637.         gh->first_l_article - 1);
  638.     else
  639.     fprintf(newsrc, " %d-%d\n", gh->first_l_article, gh->last_article);
  640. }
  641.